home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / byte-benchmarks / part03 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  46.6 KB

  1. Subject:  v22i030:  Byte Unix benchmarks, Part03/05
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 59e809aa 755afa62 4a84bcf4 0e97b252
  5.  
  6. Submitted-by: "Ben Smith @ BYTE" <ben@bytepb.byte.com>
  7. Posting-number: Volume 22, Issue 30
  8. Archive-name: byte-benchmarks/part03
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 3 (of 5)."
  17. # Contents:  bench.doc big.c dbmserv.c
  18. # Wrapped by rsalz@papaya.bbn.com on Tue May  8 08:55:32 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'bench.doc' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'bench.doc'\"
  22. else
  23. echo shar: Extracting \"'bench.doc'\" \(14682 characters\)
  24. sed "s/^X//" >'bench.doc' <<'END_OF_FILE'
  25. X@BT
  26. X
  27. X[TITLE]BYTE's UNIX Benchmarks
  28. X[DEK]Separating fact from fiction in the exploding UNIX empire
  29. X[TOC]Before you jump into the UNIX pool, see how your favorite system stacks
  30. Xup against the rest of the pack.
  31. X
  32. XBen Smith
  33. X
  34. XIn making purchase decisions, it's difficult to know whom to believe. Each
  35. Xvendor claims, predictably, that their products are better than the
  36. Xcompetition's, but how does one prove, or debunk, these claims?
  37. X  Cost and performance typically top the list of considerations for those
  38. Xseeking to purchase equipment, and while cost can be easily compared,
  39. Xperformance cannot, and comparing costs without analyzing each system's
  40. Xrelative value is a worthless exercise.
  41. X  When DOS became popular, it allowed for the development of performance
  42. Xmeasurement programs, benchmarks, that would run on any system that ran DOS.
  43. XBYTE's lab technicians set about creating their own, and the BYTE DOS
  44. Xbenchmarks were born. Dozens of systems have been clocked using these
  45. Xfacilities, and each review of a new DOS-based system includes the results of
  46. Xthese benchmarks.
  47. X  This is all very well, but while DOS is installed on a great many systems,
  48. Xit is no longer the !ITAL!only!ENDITAL! popular multi-platform operating
  49. Xsystem. User demands for greater expandability, better performance and
  50. Xmulti-tasking have turned UNIX systems into one of the fastest growing
  51. Xsegments of the market. When UNIX stepped from minicomputers to workstations,
  52. Xit established itself as the defacto OS for an exciting new breed of machine.
  53. XNow, with solid implementations for affordable Intel and Motorola-based
  54. Xplatforms, UNIX is making a name for itself in the PC realm. As UNIX finds
  55. Xits way into the mainstream, it is necessary to have the tools to objectively
  56. Xmeasure not only the performance of various hardware platforms, but of
  57. Xdifferent versions of UNIX as well.
  58. X
  59. X!SUBHED!Unix is Not MS-DOS!ENDSUBHED!
  60. XConceptually, BYTE's UNIX benchmarks are the same as BYTE's MS-DOS
  61. Xbenchmarks: We have combined evaluation of both low-level operations and
  62. Xhigh-level applications type programs to highlight the performance of the
  63. Xentire system.
  64. X  But UNIX is considerably different from MS-DOS. In the first place, it is a
  65. X!ITAL!multi!ENDITAL!-tasking, !ITAL!multi!ENDITAL!-user operating system. It
  66. Xis also portable, able to run on many different kinds of computers. MS-DOS is
  67. Xa !ITAL!single!ENDITAL!-tasking, !ITAL!single!ENDITAL!-user operating system,
  68. Xand it is intended to run on essentially one kind of computer, an IBM-PC or
  69. XPC ``clone,'' utilizing a specific class of processor from Intel. As a
  70. Xresult, the UNIX benchmarks differ from their MS-DOS counterparts. Even
  71. Xthough there are some equivalent low-level tests, you will find that even
  72. Xthese run differently; the popular Dhrystone benchmark commonly gives
  73. Xdifferent results, on the same hardware, when run under both DOS and UNIX.
  74. XThe reason? Different compilers are being used, and the underlying operating
  75. Xsystems and services are wildly different.
  76. X  Another important difference is that Microsoft is the only real source of
  77. XDOS; other suppliers simply repackage Microsoft's basic operating system
  78. Xunder other names. In contrast, there are many different kinds of UNIX, and
  79. Xwhile similarities exist (the core UNIX from Dell, Everex and Interactive
  80. XSystems are virtually the same), there are UNIX and UNIX-like operating
  81. Xsystems that differ greatly from one another. Conclusion: The UNIX benchmarks
  82. Xare evaluating the implementation of UNIX and the resident compiler as well
  83. Xas the hardware on which it is running (the MS-DOS and Apple Macintosh
  84. Xbenchmarks use a common compiler, the public-domain Small C).
  85. X  With so many variables, what is constant? Well, we have established a
  86. Xbaseline, SCO Xenix 386 version 2.3.1. running on the Everex 386/33 with 4
  87. XMbytes of RAM and an 80387 math coprocessor. While it isn't UNIX per se
  88. X(because AT&T decides which implementations may be called ``UNIX''), it is
  89. Xmore popular than any other PC UNIX implementation. It is specifically
  90. Xdesigned for 80386-based computers with full 32 bit memory access. The Everex
  91. X386/33 was chosen because it is one of today's highest performance 386
  92. Xcomputers properly configured to run the full 32 bit operating system. (Some
  93. X386 computers cannot access memory through single 32 bit operations; small
  94. Xmatter if you are just running MS-DOS, an 8 bit operating system, but serious
  95. Xif you want to run UNIX.) This combination of system and OS is timely, but
  96. Xwe'll continue to adjust the baseline as needed to reflect the installed PC
  97. Xand workstation UNIX base.
  98. X
  99. X!SUBHED!The Low Level Bench Programs!ENDSUBHED!
  100. XThe BYTE UNIX benchmarks consist of eight groups of programs: arithmetic,
  101. Xsystem calls, memory operations, disk operations, dhrystone, database
  102. Xoperations, system loading, and miscellaneous. These can be roughly divided
  103. Xinto the low-level tests (arithmetic, system calls, memory, disk, and
  104. Xdhrystone) and high-level tests (database operations, system loading, and the
  105. XC-compiler test that is part of the miscellaneous set).
  106. X  The Dhrystone test is known more formally as ``Dhrystone 2''. It performs
  107. Xno floating-point operations, but it does involve arrays, character strings,
  108. Xindirect addressing, and most of the non-floating point instructions that
  109. Xmight be found in an application program. It also includes conditional
  110. Xoperations and other common program flow controls. The output of the test is
  111. Xthe number of dhrystone loops per second. It is used in the BYTE benchmarks
  112. Xbecause of its wide selection of operations and because it is one of the most
  113. Xwidely run benchmark programs.
  114. X  A future version of the BYTE UNIX benchmarks will include the Whetstone
  115. Xbenchmark test program, as well. The Whetstone benchmark is conceptually
  116. Xsimilar to the Dhrystone, but with an emphasis on math; it is a mix of
  117. Xfloating point and integer arithmetic, function calls, array operations,
  118. Xconditionals, and transcendental function calls.
  119. X  All the arithmetic tests have the same source code with different data
  120. Xtypes substituted for the operations: register, short, int, long, float,
  121. Xdouble, and an empty loop for calculating the overhead required by the
  122. Xprogram. The actual test involves assignment, addition, subtraction,
  123. Xmultiplication, and division. Very simple. But don't bother running the float
  124. Xand double precision test unless you have a math co-processor; what takes a
  125. Xmath co-processor system 15 seconds, may take an unaided processor 30 minutes
  126. Xor more!
  127. X  The system call tests are: system call overhead, pipe throughput, pipe
  128. Xcontext switching, spawning of child processes, execl (replacement of the
  129. Xcurrent process by a new process), and file read, write, and copy. The system
  130. Xcall overhead test evaluates the time required to do iterations of
  131. X!MONO!dup()!ENDMONO!, !MONO!close()!ENDMONO!, !MONO!getpid()!ENDMONO!,
  132. X!MONO!getuid()!ENDMONO!, and !MONO!umask()!ENDMONO! calls.
  133. X  The pipe throughput test has no real counterpart in real-world programming;
  134. Xin it, a single process opens a pipe (an inter-process communications channel
  135. Xthat works rather like its plumbing namesake) to itself and spins a megabyte
  136. Xaround this short loop. You might call this the pipe overhead test. The
  137. Xcontext switching pipe test is more like a real-world application; the test
  138. Xprogram spawns a child process with which it carries on a bi-directional pipe
  139. Xconversation.
  140. X  The spawn test creates a child process which immediately dies after its own
  141. X!MONO!fork()!ENDMONO!. The process is repeated over and over. Similarly, the
  142. Xexec test is a process that repeatedly changes to a new incarnation. One of
  143. Xthe arguments passed to the new incarnation is the number of remaining
  144. Xiterations (there has to be some control, after all).
  145. X The file read, write, and copy tests capture the number of characters that
  146. Xcan be written, read, and copied in a specified time (default is 10 seconds).
  147. XIf you run this test with the minimum element (1 second), you should see a
  148. Xsignificantly higher value for all operations if your system implements disk
  149. Xcacheing. Be sure you have plenty of disk space before you run this test.
  150. X
  151. X!SUBHED!The High-Level Bench Programs!ENDSUBHED!
  152. XTo qualify as a high-level test, the test must involve operations that a
  153. Xreal-world application program might employ, including heavy use of the CPU
  154. Xand disk. At the time of writing this article, we have currently implemented
  155. Xonly the system loading and database tests, but we will be adding several new
  156. Xtests in the months ahead.
  157. X  The system loading test is a shell script that is run by 1, 2, 4, and 8
  158. Xconcurrent processes. The script consists of an alphabetic sort one file to
  159. Xanother; taking the octal dump of the result and doing a numeric sort to a
  160. Xthird file; running grep on the result of the alphabetic sort file;
  161. X!MONO!tee!ENDMONO!ing the result to a file and to !MONO!wc!ENDMONO! (word
  162. Xcount); writing the final result to a file; and removing all of the resulting
  163. Xfiles. This script was used in the original BYTE UNIX benchmarks (1983), but
  164. Xthe source file is several magnitudes larger than the original.
  165. X  The C compile and link is nothing more than that.
  166. X  The database operations consist of random read, write, and add operations
  167. Xon a database file. The operations are handled by a server process; the
  168. Xrequests come from client processes. The test is run with 1, 2, 4, and 8
  169. Xclient processes. The test employs semaphores and message queues. Semaphores
  170. Xare being used less and less these days. BSD systems use sockets instead in
  171. Xplace of both of these System V.3 IPC utilities. System V.4 offers both. This
  172. Xtest is being rewritten using sockets, but since Xenix doesn't implement
  173. Xsockets, our baseline configuration becomes instantly obsolete when we
  174. Xreplace the database test. Just another one of those little problems in
  175. Xtrying to create journalistic computer benchmarks: any program that has been
  176. Xfully debugged is probably obsolete [ Murphy, et al ].
  177. X
  178. X!SUBHED!Miscellany!ENDSUBHED!
  179. XThe remaining tests are in the miscellaneous group: Tower of Hanoi (a test of
  180. Xrecursive operations) and a test of the UNIX arbitrary precision calculator
  181. Xcalculating the square root of two to 99 decimal places.
  182. X  No doubt, we will be adding tests to this suite as we see the need to test
  183. Xand evaluate from different perspectives.
  184. X
  185. X!SUBHED!Problems in the Modern World!ENDSUBHED!
  186. XThe major problem we have had with developing the UNIX benchmark programs is
  187. Xdesigning them so that they fairly reflect the strengths and weaknesses of
  188. Xall the systems on which we anticipate using them. For example, the
  189. Xoperations should allow RISC machines to give appropriately high performance
  190. Xfor the sorts of operations that RISC is good for, and should also illustrate
  191. Ximprovements provided by faster bus speeds, better math coprocessors and the
  192. Xlike. In the case of RISC, the efficiency of the compiler is of utmost
  193. Ximportance; RISC compilers must rearrange instructions to take advantage of
  194. Xinstruction pipelining (for an overview of RISC, see BYTE, May 1988).
  195. X  The majority of the UNIX systems that we look at employ disk caching. This
  196. Xis especially important because modern UNIX includes swapping and paging out
  197. Xto disk when there is insufficient memory for a task or the number of tasks.
  198. XIt is an interesting exercise to run the disk file operations test with
  199. Xincreasingly large files and note the point at which performance drops.
  200. X
  201. X!SUBHED!How They Work!ENDSUBHED!
  202. XA 400 line Bourne shell script (!MONO!Run!ENDMONO!) administers the
  203. Xbenchmarking system. After the evaluation of the command line options, the
  204. Xbenchmarking operation for each test has three stages: parameter setup,
  205. Xtiming the execution of the test, and calculation/formatting operations (see
  206. XFigure 1). After !MONO!Run!ENDMONO! determines the parameters for the test,
  207. Xit sends a formatted description to the output file. !MONO!Run!ENDMONO! then
  208. Xinvokes the specific test by means of the UNIX command !MONO!time!ENDMONO!.
  209. XThe output of !MONO!time!ENDMONO! and any output from the test itself end up
  210. Xin a raw data file. Most tests are run six times so that any variance can be
  211. Xaveraged. On completion of a set of tests, !MONO!Run!ENDMONO! invokes a
  212. Xcleanup script, which does the statistical calculations on the raw data using
  213. Xthe !MONO!awk!ENDMONO! formatting language.
  214. X  The greater part of the benchmark programs are written in C and are
  215. Xcompiled on the test machine prior to running the tests. 
  216. X
  217. X!SUBHED!Using the Results!ENDSUBHED!
  218. XIf all you need is a raw measure of performance, then feel free to use the
  219. XDhrystone and Whetstone tests as indices of just that. But if you want to use
  220. Xthe benchmarks to evaluate a machine's ability to serve some real need, then
  221. Xyou should do the following:
  222. X1. Analyze your requirements as far as the type of computing, amount and type
  223. Xof communications I/O, and amount and type of disk I/O.
  224. X2. Score the subject machines using weighting factors that reflect your
  225. Xrequirements.
  226. X3. Generate a price vs. performance plot.
  227. X4. Use the price vs. performance, along with information about the
  228. Xreliability servicability of the hardware.
  229. X  Step 4 is really more of an art than anything else. It is extremely
  230. Ximportant, however, to not rely on price vs. performance alone.
  231. X We use our UNIX Benchmarks for doing a rough analysis and comparison of
  232. Xdivergent machines. (See figure 2, ``UNIX Machines Tested.'') As you can see,
  233. Xwe even go so far as to generate a single index number, a sort of reduction
  234. Xof all of the benchmark tests to a single value. This index is generated by
  235. Xsumming the the individual indices of the dhrystone test, the floating point
  236. Xtest, the shell test with eight concurrent processes, the C compiler time,
  237. Xthe !MONO!dc!ENDMONO! routine, and the tower of hanoi time. By definition,
  238. Xthe combined index for the baseline machine is six. Indicess above six imply
  239. Xa better overall performance than the baseline machine; indices less than
  240. Xsix, worse performance. Always keep in mind that having a single index rating
  241. Xfor a machine may make good cocktail conversation, but it is incredibly
  242. Xsimplistic. It is like reducing a complex sculptural shape to a single point;
  243. Xyou no longer can tell what you are looking at. This number doesn't reflect
  244. Xany real-world use of a UNIX system. However, the index is devised so that it
  245. Xgives an overall indication of different kinds of system operations and so is
  246. Xvaluable to our reviews.
  247. X  BYTE's UNIX benchmarking suite is small enough to port easily to any UNIX
  248. Xsystem, yet diverse and flexible enough to be useful for a wide spectrum of
  249. Xbenchmarking requirements. Besides, they're in the public domain, so they can
  250. Xbe obtained for little, if any, cost. What better reason do you need to use
  251. Xthem?
  252. END_OF_FILE
  253. if test 14682 -ne `wc -c <'bench.doc'`; then
  254.     echo shar: \"'bench.doc'\" unpacked with wrong size!
  255. fi
  256. chmod +x 'bench.doc'
  257. # end of 'bench.doc'
  258. fi
  259. if test -f 'big.c' -a "${1}" != "-c" ; then 
  260.   echo shar: Will not clobber existing file \"'big.c'\"
  261. else
  262. echo shar: Extracting \"'big.c'\" \(13750 characters\)
  263. sed "s/^X//" >'big.c' <<'END_OF_FILE'
  264. X/*******************************************************************************
  265. X *  The BYTE UNIX Benchmarks - Release 2
  266. X *          Module: big.c   SID: 2.4 4/17/90 16:45:31
  267. X *          
  268. X *******************************************************************************
  269. X * Bug reports, patches, comments, suggestions should be sent to:
  270. X *
  271. X *    Ben Smith or Rick Grehan at BYTE Magazine
  272. X *    bensmith@bixpb.UUCP    rick_g@bixpb.UUCP
  273. X *
  274. X *******************************************************************************
  275. X *  Modification Log:
  276. X *
  277. X ******************************************************************************/
  278. Xchar SCCSid[] = "@(#) @(#)big.c:2.4 -- 4/17/90 16:45:31";
  279. X/*
  280. X *  dummy code for execl test [ old version of makework.c ]
  281. X *
  282. X *  makework [ -r rate ] [ -c copyfile ] nusers
  283. X *
  284. X *  job streams are specified on standard input with lines of the form
  285. X *  full_path_name_for_command [ options ] [ <standard_input_file ]
  286. X *
  287. X *  "standard input" is send to all nuser instances of the commands in the
  288. X *  job streams at a rate not in excess of "rate" characters per second
  289. X *  per command
  290. X *
  291. X */
  292. X
  293. X#include <stdio.h>
  294. X#include <signal.h>
  295. X
  296. X#define DEF_RATE    5.0
  297. X#define GRANULE        5
  298. X#define CHUNK        60
  299. X#define MAXCHILD    12
  300. X#define MAXWORK        10
  301. X
  302. Xfloat    thres;
  303. Xfloat    est_rate = DEF_RATE;
  304. Xint    nusers;        /* number of concurrent users to be simulated by
  305. X             * this process */
  306. Xint    firstuser;    /* ordinal identification of first user for this
  307. X             * process */
  308. Xint    nwork = 0;    /* number of job streams */
  309. Xint    exit_status = 0;    /* returned to parent */
  310. Xint    sigpipe;    /* pipe write error flag */
  311. X
  312. Xstruct st_work {
  313. X    char    *cmd;        /* name of command to run */
  314. X    char    **av;        /* arguments to command */
  315. X    char    *input;        /* standard input buffer */
  316. X    int    inpsize;    /* size of standard input buffer */
  317. X    char    *outf;        /* standard output (filename) */
  318. X} work[MAXWORK];
  319. X
  320. Xstruct {
  321. X    int    xmit;    /* # characters sent */
  322. X    char    *bp;    /* std input buffer pointer */
  323. X    int    blen;    /* std input buffer length */
  324. X    int    fd;    /* stdin to command */
  325. X    int    pid;    /* child PID */
  326. X    char    *line;    /* start of input line */ 
  327. X    int    firstjob;    /* inital piece of work */
  328. X    int    thisjob;    /* current piece of work */
  329. X} child[MAXCHILD], *cp;
  330. X
  331. Xmain(argc, argv)
  332. Xint    argc;
  333. Xchar    *argv[];
  334. X{
  335. X    int        i;
  336. X    int        l;
  337. X    int        fcopy = 0;    /* fd for copy output */
  338. X    int        master = 1;    /* the REAL master, == 0 for clones */
  339. X    int        nchild;        /* no. of children for a clone to run */
  340. X    int        done;        /* count of children finished */
  341. X    int        output;        /* aggregate output char count for all
  342. X                   children */
  343. X    int        c;
  344. X    int        thiswork = 0;    /* next job stream to allocate */
  345. X    int        nch;        /* # characters to write */
  346. X    int        written;    /* # characters actully written */
  347. X    char    logname[15];    /* name of the log file(s) */
  348. X    int        onalarm();
  349. X    int        pipeerr();
  350. X    int        wrapup();
  351. X    int        grunt();
  352. X    int        pvec[2];    /* for pipes */
  353. X    char    *p;
  354. X    char    *prog;        /* my name */
  355. X
  356. X#if ! debug
  357. X    freopen("masterlog.00", "a", stderr);
  358. X#endif
  359. X    fprintf(stderr, "*** New Run ***  ");
  360. X    prog = argv[0];
  361. X    while (argc > 1 && argv[1][0] == '-')  {
  362. X    p = &argv[1][1];
  363. X    argc--;
  364. X    argv++;
  365. X    while (*p) {
  366. X        switch (*p) {
  367. X        case 'r':
  368. X            est_rate = atoi(argv[1]);
  369. X            sscanf(argv[1], "%f", &est_rate);
  370. X            if (est_rate <= 0) {
  371. X                fprintf(stderr, "%s: bad rate, reset to %.2f chars/sec\n", prog, DEF_RATE);
  372. X                est_rate = DEF_RATE;
  373. X            }
  374. X            argc--;
  375. X            argv++;
  376. X            break;
  377. X
  378. X        case 'c':
  379. X            fcopy = open(argv[1], 1);
  380. X            if (fcopy < 0)
  381. X                fcopy = creat(argv[1], 0600);
  382. X            if (fcopy < 0) {
  383. X                fprintf(stderr, "%s: cannot open copy file '%s'\n",
  384. X                prog, argv[1]);
  385. X                exit(2);
  386. X            }
  387. X            lseek(fcopy, 0L, 2);    /* append at end of file */
  388. X            argc--;
  389. X            argv++;
  390. X            break;
  391. X
  392. X        default:
  393. X        fprintf(stderr, "%s: bad flag '%c'\n", prog, *p);
  394. X            exit(4);
  395. X        }
  396. X        p++;
  397. X    }
  398. X    }
  399. X    
  400. X    if (argc < 2) {
  401. X    fprintf(stderr, "%s: missing nusers\n", prog);
  402. X    exit(4);
  403. X    }
  404. X
  405. X    nusers = atoi(argv[1]);
  406. X    if (nusers < 1) {
  407. X    fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]);
  408. X    exit(4);
  409. X    }
  410. X    fprintf(stderr, "%d Users\n", nusers);
  411. X    argc--;
  412. X    argv++;
  413. X
  414. X    /* build job streams */
  415. X    getwork();
  416. X#if debug
  417. X    dumpwork();
  418. X#endif
  419. X
  420. X    /* clone copies of myself to run up to MAXCHILD jobs each */
  421. X    firstuser = MAXCHILD;
  422. X    fprintf(stderr, "master pid %d\n", getpid());
  423. X    fflush(stderr);
  424. X    while (nusers > MAXCHILD) {
  425. X    fflush(stderr);
  426. X    if (nusers >= 2*MAXCHILD)
  427. X        /* the next clone must run MAXCHILD jobs */
  428. X        nchild = MAXCHILD;
  429. X    else
  430. X        /* the next clone must run the leftover jobs */
  431. X        nchild = nusers - MAXCHILD;
  432. X    if ((l = fork()) == -1) {
  433. X        /* fork failed */
  434. X        fatal("** clone fork failed **\n");
  435. X        goto bepatient;
  436. X    } else if (l > 0) {
  437. X        fprintf(stderr, "master clone pid %d\n", l);
  438. X        /* I am the master with nchild fewer jobs to run */
  439. X        nusers -= nchild;
  440. X        firstuser += MAXCHILD;
  441. X        continue;
  442. X    } else {
  443. X        /* I am a clone, run MAXCHILD jobs */
  444. X#if ! debug
  445. X        sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD);
  446. X        freopen(logname, "w", stderr);
  447. X#endif
  448. X        master = 0;
  449. X        nusers = nchild;
  450. X        break;
  451. X    }
  452. X    }
  453. X    if (master)
  454. X    firstuser = 0;
  455. X
  456. X    close(0);
  457. X    for (i = 0; i < nusers; i++ ) {
  458. X    fprintf(stderr, "user %d job %d ", firstuser+i, thiswork);
  459. X    if (pipe(pvec) == -1) {
  460. X        /* this is fatal */
  461. X        fatal("** pipe failed **\n");
  462. X        goto bepatient;
  463. X    }
  464. X    fflush(stderr);
  465. X    if ((child[i].pid = fork()) == 0) {
  466. X        int    fd;
  467. X        /* the command */
  468. X        if (pvec[0] != 0) {
  469. X        close(0);
  470. X        dup(pvec[0]);
  471. X        }
  472. X#if ! debug
  473. X        sprintf(logname, "userlog.%02d", firstuser+i);
  474. X        freopen(logname, "w", stderr);
  475. X#endif
  476. X        for (fd = 3; fd < 24; fd++)
  477. X        close(fd);
  478. X        if (work[thiswork].outf[0] != '\0') {
  479. X        /* redirect std output */
  480. X        char    *q;
  481. X        for (q = work[thiswork].outf; *q != '\n'; q++) ;
  482. X        *q = '\0';
  483. X        if (freopen(work[thiswork].outf, "w", stdout) == NULL) {
  484. X            fprintf(stderr, "makework: cannot open %s for std output\n",
  485. X            work[thiswork].outf);
  486. X            fflush(stderr);
  487. X        }
  488. X        *q = '\n';
  489. X        }
  490. X        execv(work[thiswork].cmd, work[thiswork].av);
  491. X        /* don't expect to get here! */
  492. X        fatal("** exec failed **\n");
  493. X        goto bepatient;
  494. X    }
  495. X    else if (child[i].pid == -1) {
  496. X        fatal("** fork failed **\n");
  497. X        goto bepatient;
  498. X    }
  499. X    else {
  500. X        close(pvec[0]);
  501. X        child[i].fd = pvec[1];
  502. X        child[i].line = child[i].bp = work[thiswork].input;
  503. X        child[i].blen = work[thiswork].inpsize;
  504. X        child[i].thisjob = thiswork;
  505. X        child[i].firstjob = thiswork;
  506. X        fprintf(stderr, "pid %d pipe fd %d", child[i].pid, child[i].fd);
  507. X        if (work[thiswork].outf[0] != '\0') {
  508. X        char *q;
  509. X        fprintf(stderr, " > ");
  510. X        for (q=work[thiswork].outf; *q != '\n'; q++)
  511. X            fputc(*q, stderr);
  512. X        }
  513. X        fputc('\n', stderr);
  514. X        thiswork++;
  515. X        if (thiswork >= nwork)
  516. X        thiswork = 0;
  517. X    }
  518. X    }
  519. X    fflush(stderr);
  520. X
  521. X    srand(time(0));
  522. X    thres = 0;
  523. X    done = output = 0;
  524. X    for (i = 0; i < nusers; i++) {
  525. X    if (child[i].blen == 0)
  526. X        done++;
  527. X    else
  528. X        thres += est_rate * GRANULE;
  529. X    }
  530. X    est_rate = thres;
  531. X
  532. X    signal(SIGALRM, onalarm);
  533. X    signal(SIGPIPE, pipeerr);
  534. X    alarm(GRANULE);
  535. X    while (done < nusers) {
  536. X    for (i = 0; i < nusers; i++) {
  537. X        cp = &child[i];
  538. X        if (cp->xmit >= cp->blen) continue;
  539. X        l = rand() % CHUNK + 1;    /* 1-CHUNK chars */
  540. X        if (l == 0) continue;
  541. X        if (cp->xmit + l > cp->blen)
  542. X        l = cp->blen - cp->xmit;
  543. X        p = cp->bp;
  544. X        cp->bp += l;
  545. X        cp->xmit += l;
  546. X#if debug
  547. X        fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit);
  548. X#endif
  549. X        while (p < cp->bp) {
  550. X        if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) {
  551. X            /* write it out */
  552. X            nch = p - cp->line + 1;
  553. X            if ((written = write(cp->fd, cp->line, nch)) != nch) {
  554. X            /* argh! */
  555. X            cp->line[nch] = '\0';
  556. X            fprintf(stderr, "user %d job %d cmd %s ",
  557. X                firstuser+i, cp->thisjob, cp->line);
  558. X             fprintf(stderr, "write(,,%d) returns %d\n", nch, written);
  559. X            if (sigpipe)
  560. X                fatal("** SIGPIPE error **\n");
  561. X            else
  562. X                fatal("** write error **\n");
  563. X            goto bepatient;
  564. X
  565. X            }
  566. X            if (fcopy)
  567. X            write(fcopy, cp->line, p - cp->line + 1);
  568. X#if debug
  569. X            fprintf(stderr, "child %d gets \"", i);
  570. X            {
  571. X            char *q = cp->line;
  572. X            while (q <= p) {
  573. X                if (*q >= ' ' && *q <= '~')
  574. X                    fputc(*q, stderr);
  575. X                else
  576. X                    fprintf(stderr, "\\%03o", *q);
  577. X                q++;
  578. X            }
  579. X            }
  580. X            fputc('"', stderr);
  581. X#endif
  582. X            cp->line = &p[1];
  583. X        }
  584. X        p++;
  585. X        }
  586. X        if (cp->xmit >= cp->blen) {
  587. X        done++;
  588. X        close(cp->fd);
  589. X#if debug
  590. X    fprintf(stderr, "child %d, close std input\n", i);
  591. X#endif
  592. X        }
  593. X        output += l;
  594. X    }
  595. X    while (output > thres) {
  596. X        pause();
  597. X#if debug
  598. X        fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done);
  599. X#endif
  600. X    }
  601. X    }
  602. X
  603. Xbepatient:
  604. X    alarm(0);
  605. X/****
  606. X *  If everything is going OK, we should simply be able to keep
  607. X *  looping unitil 'wait' fails, however some descendent process may
  608. X *  be in a state from which it can never exit, and so a timeout
  609. X *  is used.
  610. X *  5 minutes should be ample, since the time to run all jobs is of
  611. X *  the order of 5-10 minutes, however some machines are painfully slow,
  612. X *  so the timeout has been set at 20 minutes (1200 seconds).
  613. X ****/
  614. X    signal(SIGALRM, grunt);
  615. X    alarm(1200);
  616. X    while ((c = wait(&l)) != -1) {
  617. X        for (i = 0; i < nusers; i++) {
  618. X        if (c == child[i].pid) {
  619. X        fprintf(stderr, "user %d job %d pid %d done", firstuser+i, child[i].thisjob, c);
  620. X        if (l != 0) {
  621. X            if (l & 0x7f)
  622. X            fprintf(stderr, " status %d", l & 0x7f);
  623. X            if (l & 0xff00)
  624. X            fprintf(stderr, " exit code %d", (l>>8) & 0xff);
  625. X            exit_status = 4;
  626. X        }
  627. X        fputc('\n', stderr);
  628. X        c = child[i].pid = -1;
  629. X        break;
  630. X        }
  631. X    }
  632. X    if (c != -1) {
  633. X        fprintf(stderr, "master clone done, pid %d ", c);
  634. X        if (l != 0) {
  635. X        if (l & 0x7f)
  636. X            fprintf(stderr, " status %d", l & 0x7f);
  637. X        if (l & 0xff00)
  638. X            fprintf(stderr, " exit code %d", (l>>8) & 0xff);
  639. X        exit_status = 4;
  640. X        }
  641. X        fputc('\n', stderr);
  642. X    }
  643. X    }
  644. X    alarm(0);
  645. X    wrapup("Finished waiting ...");
  646. X
  647. X
  648. X}
  649. X
  650. Xonalarm()
  651. X{
  652. X    thres += est_rate;
  653. X    signal(SIGALRM, onalarm);
  654. X    alarm(GRANULE);
  655. X}
  656. X
  657. Xgrunt()
  658. X{
  659. X    /* timeout after label "bepatient" in main */
  660. X    exit_status = 4;
  661. X    wrapup("Timed out waiting for jobs to finish ...");
  662. X}
  663. X
  664. Xpipeerr()
  665. X{
  666. X    sigpipe++;
  667. X}
  668. X
  669. Xwrapup(reason)
  670. Xchar    *reason;
  671. X{
  672. X    int i;
  673. X    int killed = 0;
  674. X    fflush(stderr);
  675. X    for (i = 0; i < nusers; i++) {
  676. X    if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
  677. X        if (!killed) {
  678. X        killed++;
  679. X        fprintf(stderr, "%s\n", reason);
  680. X        fflush(stderr);
  681. X        }
  682. X        fprintf(stderr, "user %d job %d pid %d killed off\n", firstuser+i, child[i].thisjob, child[i].pid);
  683. X    fflush(stderr);
  684. X    }
  685. X    }
  686. X    exit(exit_status);
  687. X}
  688. X
  689. Xgetwork()
  690. X{
  691. X    int            i;
  692. X    int            f;
  693. X    int            ac;
  694. X    char        *lp;
  695. X    char        *q;
  696. X    struct st_work    *w;
  697. X    char        line[512];
  698. X    char        c;
  699. X    char        *malloc(), *realloc();
  700. X
  701. X    while (gets(line) != NULL) {
  702. X    if (nwork >= MAXWORK) {
  703. X        fprintf(stderr, stderr, "Too many jobs specified, .. increase MAXWORK\n");
  704. X        exit(4);
  705. X    }
  706. X    w = &work[nwork];
  707. X    lp = line;
  708. X    i = 1;
  709. X    while (*lp && *lp != ' ') {
  710. X        i++;
  711. X        lp++;
  712. X    }
  713. X    w->cmd = (char *)malloc(i);
  714. X    strncpy(w->cmd, line, i-1);
  715. X    w->cmd[i-1] = '\0';
  716. X    w->inpsize = 0;
  717. X    w->input = "";
  718. X    /* start to build arg list */
  719. X    ac = 2;
  720. X    w->av = (char **)malloc(2*sizeof(char *));
  721. X    q = w->cmd;
  722. X    while (*q) q++;
  723. X    q--;
  724. X    while (q >= w->cmd) {
  725. X        if (*q == '/') {
  726. X        q++;
  727. X        break;
  728. X        }
  729. X        q--;
  730. X    }
  731. X    w->av[0] = q;
  732. X    while (*lp) {
  733. X        if (*lp == ' ') {
  734. X        /* space */
  735. X        lp++;
  736. X        continue;
  737. X        }
  738. X        else if (*lp == '<') {
  739. X        /* standard input for this job */
  740. X        q = ++lp;
  741. X        while (*lp && *lp != ' ') lp++;
  742. X        c = *lp;
  743. X        *lp = '\0';
  744. X        if ((f = open(q, 0)) == -1) {
  745. X            fprintf(stderr, "cannot open input file (%s) for job %d\n",
  746. X                q, nwork);
  747. X            exit(4);
  748. X        }
  749. X        /* gobble input */
  750. X        w->input = (char *)malloc(512);
  751. X        while ((i = read(f, &w->input[w->inpsize], 512)) > 0) {
  752. X            w->inpsize += i;
  753. X            w->input = (char *)realloc(w->input, w->inpsize+512);
  754. X        }
  755. X        w->input = (char *)realloc(w->input, w->inpsize);
  756. X        close(f);
  757. X        /* extract stdout file name from line beginning "C=" */
  758. X        w->outf = "";
  759. X        for (q = w->input; q < &w->input[w->inpsize-10]; q++) {
  760. X            if (*q == '\n' && strncmp(&q[1], "C=", 2) == 0) {
  761. X            w->outf = &q[3];
  762. X            break;
  763. X            }
  764. X        }
  765. X#if debug
  766. X        if (*w->outf) {
  767. X            fprintf(stderr, "stdout->");
  768. X            for (q=w->outf; *q != '\n'; q++)
  769. X            fputc(*q, stderr);
  770. X            fputc('\n', stderr);
  771. X        }
  772. X#endif
  773. X        }
  774. X        else {
  775. X        /* a command option */
  776. X        ac++;
  777. X        w->av = (char **)realloc(w->av, ac*sizeof(char *));
  778. X        q = lp;
  779. X        i = 1;
  780. X        while (*lp && *lp != ' ') {
  781. X            lp++;
  782. X            i++;
  783. X        }
  784. X        w->av[ac-2] = (char *)malloc(i);
  785. X        strncpy(w->av[ac-2], q, i-1);
  786. X        w->av[ac-2][i-1] = '\0';
  787. X        }
  788. X    }
  789. X    w->av[ac-1] = (char *)0;
  790. X    nwork++;
  791. X    }
  792. X}
  793. X
  794. X#if debug
  795. Xdumpwork()
  796. X{
  797. X    int        i;
  798. X    int        j;
  799. X
  800. X    for (i = 0; i < nwork; i++) {
  801. X    fprintf(stderr, "job %d: cmd: %s\n", i, work[i].cmd);
  802. X    j = 0;
  803. X    while (work[i].av[j]) {
  804. X        fprintf(stderr, "argv[%d]: %s\n", j, work[i].av[j]);
  805. X        j++;
  806. X    }
  807. X    fprintf(stderr, "input: %d chars text: ", work[i].inpsize);
  808. X    if (work[i].input == (char *)0)
  809. X        fprintf(stderr, "<NULL>\n");
  810. X    else {
  811. X            register char    *pend;
  812. X            char        *p;
  813. X        char        c;
  814. X        p = work[i].input;
  815. X        while (*p) {
  816. X            pend = p;
  817. X            while (*pend && *pend != '\n')
  818. X                pend++;
  819. X            c = *pend;
  820. X            *pend = '\0';
  821. X            fprintf(stderr, "%s\n", p);
  822. X            *pend = c;
  823. X            p = &pend[1];
  824. X        }
  825. X    }
  826. X    }
  827. X}
  828. X#endif
  829. X
  830. Xfatal(s)
  831. Xchar *s;
  832. X{
  833. X    int    i;
  834. X    fprintf(stderr, s);
  835. X    fflush(stderr);
  836. X    perror("Reason?");
  837. X    fflush(stderr);
  838. X    for (i = 0; i < nusers; i++) {
  839. X    if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
  840. X        fprintf(stderr, "pid %d killed off\n", child[i].pid);
  841. X        fflush(stderr);
  842. X    }
  843. X    }
  844. X    exit_status = 4;
  845. X    return;
  846. X}
  847. END_OF_FILE
  848. if test 13750 -ne `wc -c <'big.c'`; then
  849.     echo shar: \"'big.c'\" unpacked with wrong size!
  850. fi
  851. chmod +x 'big.c'
  852. # end of 'big.c'
  853. fi
  854. if test -f 'dbmserv.c' -a "${1}" != "-c" ; then 
  855.   echo shar: Will not clobber existing file \"'dbmserv.c'\"
  856. else
  857. echo shar: Extracting \"'dbmserv.c'\" \(15460 characters\)
  858. sed "s/^X//" >'dbmserv.c' <<'END_OF_FILE'
  859. X/*******************************************************************************
  860. X *  The BYTE UNIX Benchmarks - Release 2
  861. X *          Module: dbmserv.c   SID: 2.4 4/17/90 16:45:37
  862. X *          
  863. X *******************************************************************************
  864. X * Bug reports, patches, comments, suggestions should be sent to:
  865. X *
  866. X *    Ben Smith or Rick Grehan at BYTE Magazine
  867. X *    bensmith@bixpb.UUCP    rick_g@bixpb.UUCP
  868. X *
  869. X *******************************************************************************
  870. X *  Modification Log:
  871. X *  change output to stdout 4/13/89 ben
  872. X *  errors to stderr 5/24/89 ben
  873. X *  added activity counters and ifdef time output
  874. X *  7/6/89 - Removed global semaphore use.  Callers pid now goes
  875. X *   into type field of message.  Semaphore now only controls
  876. X *   append operation and indicates presence of server.  RG
  877. X * 7/11/89 - Semaphores are back.  One controls extending the file,
  878. X *   the other controls the number of people simultaneously allowed
  879. X *   on the request queue.  This latter semaphore must be tuned for
  880. X *   a particular system to keep it from deadlocking.
  881. X******************************************************************************/
  882. X/*
  883. X * Multi-user DBMS simulation.
  884. X * Server
  885. X * Database has the form:
  886. X * IIIINNNNNNNNNNNNNNNNNNNNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPPPPPPPPPP
  887. X * Where IIII is the 4-digit id number (0-padded)
  888. X *       NN... is the 20-character name
  889. X *       AA... is the 40-character address
  890. X *       PP... is the 10-character phone number
  891. X * Records are accessed by ID number (1 is the 0th record, 2 is 1st..etc.)
  892. X */
  893. Xchar id[] = "@(#) @(#)dbmserv.c:1.5 -- 7/10/89 18:54:58";
  894. X
  895. X#include <stdio.h>
  896. X#include <setjmp.h>
  897. X#include <ctype.h>
  898. X#include <errno.h>
  899. X#include <sys/types.h>
  900. X#include <sys/signal.h>
  901. X#include <sys/ipc.h>
  902. X#include <sys/msg.h>
  903. X#include <sys/param.h>
  904. X#include <sys/sem.h>
  905. X
  906. X#ifdef VERBOSE
  907. X#define DEBUG  /* remove after debugging */
  908. X#endif
  909. X
  910. X#define ERROR (-1)
  911. X#define QERR 1
  912. X
  913. X#define SEEK_SET 0
  914. X#define SEEK_END 2
  915. X
  916. X#define RMODE 0644
  917. X#define WMODE 0666
  918. X
  919. X/*
  920. X** Record definitions.
  921. X*/
  922. X
  923. X#define IDLEN 4
  924. X#define NAMELEN 20
  925. X#define ADDRLEN 40
  926. X#define PHONLEN 10
  927. X#define RECLEN  74    /* Sum of the above. */
  928. X
  929. X/*
  930. X** Queue and semaphore names. Queues are neamed from client's
  931. X**  point of view
  932. X*/
  933. X#define    RQUEUE    "WRIT"        /* Read queue */
  934. X#define WQUEUE    "READ"        /* Write queue */
  935. X#define SEMA    "SEMA"        /* Semaphore */
  936. X/*
  937. X** Message types.
  938. X*/
  939. X#define READREQ    1        /* Read a record */
  940. X#define WRITEREQ 2        /* Write a record */
  941. X#define ADDREQ 3        /* Add a new record */
  942. X#define GETLREQ 4        /* Get largest record number */
  943. X#define RESULTREQ 10        /* Record contains results figures */
  944. X                /* Results are stored as:
  945. X                *  nnnnnnnnnnmmmmmmmmmm
  946. X                *   n = total time
  947. X                *   m = number of errors
  948. X                */
  949. X#define DIEREQ 99        /* Orders server to terminate. */
  950. X
  951. X/*
  952. X** Return codes.
  953. X*/
  954. X#define AOK 1            /* Request met ok */
  955. X#define DERR_RNF 2        /* Record not found */
  956. X#define DERR_RAE 3        /* Record already exists */
  957. X#define DERR_WRD 4        /* Unexplainable error */
  958. X#define DERR_UNK 9        /* Unknown request type */
  959. X/*
  960. X** Structures.
  961. X*/
  962. X
  963. Xtypedef struct {
  964. X    int request;        /* Request type and response code */
  965. X    char recdat[RECLEN];    /* DBMS record data */
  966. X} msgdata;
  967. X
  968. Xtypedef struct {
  969. X    long type;        /* Holds caller's pid */
  970. X    msgdata data;        /* Pointer to request and data */
  971. X} amess;
  972. X
  973. X
  974. Xstruct ticker { unsigned long real,
  975. X               system,
  976. X               cpu; };
  977. X/*
  978. X** Structure instances.
  979. X*/
  980. Xamess hisreq;
  981. Xamess myresp;
  982. X
  983. X/* Semaphore operations for initially unlocking the queue and
  984. X** append semaphores.  */
  985. X
  986. Xstruct sembuf unlock0;
  987. Xstruct sembuf unlock1 = {1 , 1, SEM_UNDO};
  988. X
  989. XFILE *dbfp;            /* Pointer for database file */
  990. Xint readq;            /* ID of read queue */
  991. Xint writeq;            /* ID of write queue */
  992. Xint qsize;            /* Size of read/write queues */
  993. Xint qsema;            /* ID of queue semaphore */
  994. Xjmp_buf myjump;            /* Jump buffer for signals */
  995. X#ifdef VERBOSE
  996. Xstruct ticker total_time = {0L, 0L, 0L}; /* Total time */
  997. X#endif
  998. Xunsigned long rd_cnt,         /* read request counter */
  999. X          wr_cnt,        /* write request counter */
  1000. X          ad_cnt,        /* add request counter */
  1001. X          gt_cnt,        /* get request counter */
  1002. X          rs_cnt;        /* result request counter */
  1003. Xunsigned long errcnt;        /* Total error count */
  1004. Xunsigned long total_tasks;    /* Total number of tasks logged in */
  1005. X
  1006. Xextern int errno;
  1007. X
  1008. X/*
  1009. X** Function defs.
  1010. X*/
  1011. Xint capt_sig();
  1012. Xkey_t makey();
  1013. X
  1014. X
  1015. X/******************************************************************
  1016. X         #    #    ##       #    #    #
  1017. X         ##  ##   #  #      #    ##   #
  1018. X         # ## #  #    #     #    # #  #
  1019. X         #    #  ######     #    #  # #
  1020. X         #    #  #    #     #    #   ##
  1021. X         #    #  #    #     #    #    #
  1022. X********************************************************************/
  1023. X
  1024. Xmain(argc,argv,envp)
  1025. Xint argc;
  1026. Xchar *argv[];
  1027. Xchar **envp;
  1028. X
  1029. X{
  1030. X
  1031. X    /*
  1032. X    ** User must specify database name and queue size.
  1033. X    */
  1034. X    if(argc<3)
  1035. X    {
  1036. X        fprintf(stderr,"usage: %s dbasefile queuesize\n",argv[0]);
  1037. X        exit(1);
  1038. X    }
  1039. X
  1040. X    /*
  1041. X    ** The file must already exist.
  1042. X    */
  1043. X    if((dbfp=fopen(argv[1],"r+"))==(FILE *)NULL)
  1044. X    {
  1045. X        fprintf(stderr,"**Open error on: %s\n",argv[1]);
  1046. X        exit(1);
  1047. X    }
  1048. X
  1049. X    /*
  1050. X    ** Get queuesize value.
  1051. X    */
  1052. X    if((qsize=atoi(argv[2]))<=0)
  1053. X    {
  1054. X        fprintf(stderr,"**Illegal queue size\n");
  1055. X        exit(1);
  1056. X    }
  1057. X    unlock0.sem_num = 0;        /* Build unlock structure */
  1058. X    unlock0.sem_op = (short)qsize;
  1059. X    unlock0.sem_flg = (short)SEM_UNDO;
  1060. X
  1061. X    /*
  1062. X    ** Set up the message queues.
  1063. X    */
  1064. X    if((readq=msgget(makey(RQUEUE),IPC_CREAT|IPC_EXCL|RMODE))==
  1065. X          ERROR)
  1066. X    {
  1067. X        qerror("**Cannot create read queue");
  1068. X        cleanup();
  1069. X        exit(1);
  1070. X    }
  1071. X
  1072. X    if((writeq=msgget(makey(WQUEUE),IPC_CREAT|IPC_EXCL|WMODE))==
  1073. X           ERROR)
  1074. X    {
  1075. X        qerror("**Cannot create write queue");
  1076. X        cleanup();
  1077. X        exit(1);
  1078. X    }
  1079. X
  1080. X    /*
  1081. X    ** Initialize stuff.
  1082. X    */
  1083. X    errcnt=0L;
  1084. X    total_tasks=0L;
  1085. X    rd_cnt=0L;
  1086. X    wr_cnt=0L;
  1087. X    ad_cnt=0L;
  1088. X    gt_cnt=0L;
  1089. X    rs_cnt=0L;
  1090. X
  1091. X    /*
  1092. X    ** Set up the semaphores and unlock them (2 semaphores in the set).
  1093. X    */
  1094. X    if((qsema=semget(makey(SEMA),2,IPC_CREAT|IPC_EXCL|WMODE))==
  1095. X        ERROR)
  1096. X    {
  1097. X        serror("**Cannot create semaphore");
  1098. X        cleanup();
  1099. X        exit(1);
  1100. X    }
  1101. X    if((semop(qsema,&unlock1,1)==ERROR) ||
  1102. X        (semop(qsema,&unlock0,1)==ERROR))
  1103. X    {
  1104. X        serror("Unlocking semaphore");
  1105. X        cleanup();
  1106. X        exit(1);
  1107. X    }
  1108. X
  1109. X    /*
  1110. X    ** Service requests from the outside world.
  1111. X    */
  1112. X    if(servicer())
  1113. X    {
  1114. X        fprintf(stderr,"**Server error**\n");
  1115. X        fprintf(stderr,"**Errcode: %d\n",errno);
  1116. X        fprintf(stderr,"**REQ: %ld\n",hisreq.type);
  1117. X    }
  1118. X
  1119. X    /*
  1120. X    ** Output results.
  1121. X    */
  1122. X       {
  1123. X#ifdef VERBOSE
  1124. X       fprintf(stdout,"Time: cpu %ld   system %ld  real %ld\n",
  1125. X        total_time.cpu, total_time.system, total_time.real);
  1126. X       fprintf(stdout,"Error : %ld  Tasks logged: %ld\n",
  1127. X          errcnt, total_tasks);
  1128. X       fprintf(stdout,
  1129. X" %ld read; %ld write; %ld add; %ld get-last; %ld result: %ld errors\n",
  1130. X        rd_cnt, wr_cnt, ad_cnt, gt_cnt, rs_cnt, errcnt);
  1131. X#endif
  1132. X       }
  1133. X
  1134. X    /*
  1135. X    ** Close everything down.
  1136. X    */
  1137. X    cleanup();
  1138. X    exit(0);            /* Good night, ladies. */
  1139. X}
  1140. X
  1141. X/**************************** servicer *********************
  1142. X** servicer()
  1143. X** This routine handles all the requests coming in on the
  1144. X** read message queue.  Responses are sent along the write
  1145. X** message queque.
  1146. X*************************************************************/
  1147. Xservicer()
  1148. X{
  1149. X#ifdef VERBOSE
  1150. X    unsigned long cpu_time,system_time,real_time;
  1151. X#endif
  1152. X    unsigned long aderr;
  1153. X    char idnum[IDLEN+1];
  1154. X    char buff[RECLEN+1];
  1155. X    int rcod;
  1156. X
  1157. X    /*
  1158. X    ** First set all the signals to capture.
  1159. X    */
  1160. X    setsignals();
  1161. X
  1162. X    /*
  1163. X    ** Build a longjump.
  1164. X    */
  1165. X    if(setjmp(myjump)!=0)
  1166. X        return(0);
  1167. X
  1168. X    /*
  1169. X    ** Now loop and process messages.
  1170. X    */
  1171. X    while(1)
  1172. X    {
  1173. X        if(msgrcv(readq,&hisreq,RECLEN,0,MSG_NOERROR)<0)
  1174. X            return(QERR);    /* Error return */
  1175. X#ifdef DEBUG
  1176. Xprintf("receiving %d requwest\n",hisreq.data.request);
  1177. X#endif
  1178. X
  1179. X
  1180. X        switch(hisreq.data.request)
  1181. X        {
  1182. X
  1183. X        /*
  1184. X        ** Read operation.
  1185. X        */
  1186. X        case READREQ:
  1187. X            ++rd_cnt;
  1188. X            strncpy(idnum,hisreq.data.recdat,4);
  1189. X            rcod=doread(idnum,buff);
  1190. X            if(rcod==AOK)
  1191. X              strncpy(myresp.data.recdat,buff,RECLEN);
  1192. X            myresp.data.request=rcod;
  1193. X            myresp.type=hisreq.type;
  1194. X            if(msgsnd(writeq,&myresp,RECLEN,0)<0)
  1195. X                return(QERR);
  1196. X#ifdef DEBUG
  1197. Xprintf("returning response\n");
  1198. X#endif
  1199. X
  1200. X            break;
  1201. X
  1202. X        /*
  1203. X        ** Write operation.
  1204. X        */
  1205. X        case WRITEREQ:
  1206. X            ++wr_cnt;
  1207. X            myresp.data.request=(long)dowrite(hisreq.data.recdat);
  1208. X            myresp.type=hisreq.type;
  1209. X            if(msgsnd(writeq,&myresp,RECLEN,0)<0)
  1210. X                return(QERR);
  1211. X            break;
  1212. X
  1213. X        /*
  1214. X        ** Add operation.
  1215. X        */
  1216. X        case ADDREQ:
  1217. X            ++ad_cnt;
  1218. X            myresp.data.request=(long)doadd(hisreq.data.recdat);
  1219. X            myresp.type=hisreq.type;
  1220. X            if(msgsnd(writeq,&myresp,RECLEN,0)<0)
  1221. X                return(QERR);
  1222. X            break;
  1223. X
  1224. X        /*
  1225. X        ** Get-last-record-in-file operation.
  1226. X        */
  1227. X        case GETLREQ:
  1228. X            ++gt_cnt;
  1229. X            myresp.data.request=(long)dotell(myresp.data.recdat);
  1230. X            myresp.type=hisreq.type;
  1231. X            if(msgsnd(writeq,&myresp,RECLEN,0)<0)
  1232. X                return(QERR);
  1233. X            break;
  1234. X
  1235. X        /*
  1236. X        ** Record task's results operation.
  1237. X        ** Note that this operation requires no
  1238. X        ** response.
  1239. X        */
  1240. X        case RESULTREQ:
  1241. X            ++rs_cnt;
  1242. X#ifdef VERBOSE
  1243. X            sscanf(hisreq.data.recdat,"%ld %ld %ld %d",
  1244. X                &cpu_time,&system_time,&real_time,&aderr);
  1245. X            total_time.cpu+=cpu_time;
  1246. X            total_time.system+=system_time;
  1247. X            total_time.real+=real_time;
  1248. X#else
  1249. X            sscanf(hisreq.data.recdat,"%d", &aderr);
  1250. X#endif
  1251. X            errcnt+=aderr;
  1252. X            total_tasks++;
  1253. X            break;
  1254. X
  1255. X        /*
  1256. X        ** We have been asked to leave.
  1257. X        */
  1258. X        case DIEREQ:
  1259. X            return(0);
  1260. X
  1261. X        /*
  1262. X        ** Eh?
  1263. X        */
  1264. X        default:
  1265. X            myresp.data.request=DERR_UNK;
  1266. X            myresp.type=hisreq.type;
  1267. X            if(msgsnd(writeq,&myresp,RECLEN,0)<0)
  1268. X                return(QERR);
  1269. X            break;
  1270. X        }
  1271. X    }
  1272. X}
  1273. X
  1274. X/**************************** doread *********************
  1275. X** Perform a read request.
  1276. X*************************************************************/
  1277. Xdoread(idnum,buff)
  1278. Xchar idnum[IDLEN+1];
  1279. Xchar buff[RECLEN];
  1280. X{
  1281. X    long offset;
  1282. X
  1283. X    /*
  1284. X    ** Calculate offset.
  1285. X    */
  1286. X    idnum[IDLEN]='\0';
  1287. X    offset=(atol(idnum)-1)*(long)RECLEN;
  1288. X    if(offset<0L) return(DERR_RNF);        /* Illegal offset */
  1289. X
  1290. X    if( (fseek(dbfp,offset,SEEK_SET)!=0) ||
  1291. X        (fread(buff,RECLEN,1,dbfp)!=1) )
  1292. X    return(DERR_RNF);            /* Seek or read failed */
  1293. X
  1294. X    return(AOK);                /* No problems */
  1295. X}
  1296. X
  1297. X/**************************** dowrite *********************
  1298. X** Perform a write request.
  1299. X*************************************************************/
  1300. Xdowrite(buff)
  1301. Xchar buff[RECLEN];
  1302. X{
  1303. X    char idnum[IDLEN+1];
  1304. X    long offset;
  1305. X
  1306. X    strncpy(idnum,buff,4);            /* Get id number */
  1307. X
  1308. X    /*
  1309. X    ** Calculate offset.
  1310. X    */
  1311. X    idnum[IDLEN]='\0';
  1312. X    offset=(atol(idnum)-1)*(long)RECLEN;
  1313. X    if(offset<0L) return(DERR_RNF);        /* Illegal offset */
  1314. X
  1315. X    if((fseek(dbfp,offset,SEEK_SET)!=0) ||
  1316. X        (fwrite(buff,RECLEN,1,dbfp)!=1))
  1317. X       return(DERR_RNF);
  1318. X
  1319. X    return(AOK);
  1320. X}
  1321. X
  1322. X/**************************** doadd *********************
  1323. X** Perform an add request.
  1324. X*************************************************************/
  1325. Xdoadd(buff)
  1326. Xchar buff[RECLEN];
  1327. X{
  1328. X
  1329. X    long offset;
  1330. X    
  1331. X    /* Seek to the end of the file. */
  1332. X    if(fseek(dbfp,0L,SEEK_END)!=0)
  1333. X        return(DERR_WRD);        /* Huh? */
  1334. X
  1335. X    /* Get offset -- we presume caller has proper id set */
  1336. X    offset=ftell(dbfp);
  1337. X    if (fwrite(buff,RECLEN,1,dbfp)!=1)
  1338. X        return(DERR_RNF);        /* Failed write */
  1339. X    
  1340. X    return(AOK);
  1341. X}
  1342. X
  1343. X/**************************** dotell *********************
  1344. X** Perform a "tell" request.
  1345. X** Returns highest current id number in file.
  1346. X*************************************************************/
  1347. Xdotell(buff)
  1348. Xchar buff[RECLEN];
  1349. X{
  1350. X    
  1351. X    long offset;
  1352. X    
  1353. X    /* Seek to the end of the file. */
  1354. X    if(fseek(dbfp,0L,SEEK_END)!=0)
  1355. X        return(DERR_WRD);        /* Huh? */
  1356. X
  1357. X    /* Get offset and calculate new id number */
  1358. X    offset=ftell(dbfp);
  1359. X    sprintf(buff,"%#04ld",(offset/(long)RECLEN));
  1360. X    
  1361. X    return(AOK);
  1362. X}
  1363. X
  1364. X/**************************** setsignals *********************
  1365. X** Set up all the signals we want to capture or ignore.
  1366. X*************************************************************/
  1367. Xsetsignals()
  1368. X{
  1369. Xstatic int diehard();
  1370. X
  1371. X    /*
  1372. X    ** Ignore hangup and interrupt.
  1373. X    */
  1374. X    signal(SIGHUP, diehard);
  1375. X    signal(SIGINT, diehard);
  1376. X
  1377. X    /*
  1378. X    ** Capture the rest.
  1379. X    */
  1380. X    signal(SIGQUIT, capt_sig);
  1381. X    signal(SIGILL, capt_sig);
  1382. X    signal(SIGTRAP, capt_sig);
  1383. X    signal(SIGIOT, capt_sig);
  1384. X    signal(SIGEMT, capt_sig);
  1385. X    signal(SIGFPE, capt_sig);
  1386. X    signal(SIGBUS, capt_sig);
  1387. X    signal(SIGSEGV, capt_sig);
  1388. X    signal(SIGSYS, capt_sig);
  1389. X    signal(SIGPIPE, capt_sig);
  1390. X    signal(SIGALRM, capt_sig);
  1391. X    signal(SIGTERM, capt_sig);
  1392. X    signal(SIGUSR1, capt_sig);
  1393. X    signal(SIGUSR2, capt_sig);
  1394. X
  1395. X    return(0);
  1396. X}
  1397. X
  1398. X/********************** capt_sig ****************************
  1399. X** Capture signals.
  1400. X** This just performs the long jump and blasts us out.
  1401. X*************************************************************/
  1402. Xstatic int capt_sig(sign)
  1403. Xint sign;
  1404. X{
  1405. X    longjmp(myjump,sign);
  1406. X}
  1407. X
  1408. X/*************************** diehard ************************
  1409. Xfor kills and other such interrupts: cleanup and exit
  1410. X*************************************************************/
  1411. Xstatic int diehard()
  1412. X{
  1413. Xcleanup();
  1414. Xexit(1);
  1415. X}
  1416. X
  1417. X/*************************** cleanup *************************
  1418. X** Clean up after yourself.
  1419. X** Close open files, release queues and semaphore.
  1420. X**************************************************************/
  1421. Xcleanup()
  1422. X{
  1423. X    fclose(dbfp);            /* Close the database file. */
  1424. X    msgctl(readq,IPC_RMID);        /* Close read queue. */
  1425. X    msgctl(writeq,IPC_RMID);    /* Close write queue. */
  1426. X    semctl(qsema,0,IPC_RMID);    /* Release semaphore. */
  1427. X    return(0);
  1428. X}
  1429. X
  1430. X/******************* makey **************************************
  1431. X** Following routine converts an ASCII string to a key_t value.
  1432. X** This routine originally appeared in ADVANCED PROGRAMMERS GUIDE
  1433. X** TO UNIX SYSTEM V by R. Thomas, PHD; L. R. Rogers, and J. L. Yates.
  1434. X** Osborne McGraw Hill.
  1435. X******************************************************************/
  1436. Xkey_t makey(p)
  1437. Xchar *p;
  1438. X{
  1439. X    key_t keyv;
  1440. X    int i;
  1441. X
  1442. X    if(isnumber(p))
  1443. X        keyv = (key_t)atol(p);
  1444. X    else
  1445. X    {
  1446. X        keyv=(key_t)0;
  1447. X        for(i=0;i<sizeof(key_t) && p[i];i++)
  1448. X            keyv=(keyv << 8) | p[i];
  1449. X    }
  1450. X    return(keyv);
  1451. X}
  1452. X
  1453. X/********************** isnumber ***************************/
  1454. Xint isnumber(p)
  1455. Xchar *p;
  1456. X{
  1457. X    for( ; *p && isdigit(*p); p++) ;
  1458. X    return(*p ? 0 : 1);
  1459. X}
  1460. X
  1461. X/******************************** qerror **********************
  1462. X ** prints out the errormessage associate with a queue
  1463. X ***************************************************************/
  1464. Xqerror(s)
  1465. Xchar *s; /* message prefix string */
  1466. X{
  1467. Xextern int errno;
  1468. X
  1469. Xfprintf(stderr,"QUEUE ERROR: %s:\n     ",s);
  1470. Xswitch(errno)
  1471. X   {
  1472. X   case EACCES: fprintf(stderr,
  1473. X       "message queue exists, but locked out (EACCES)\n");
  1474. X       break;
  1475. X   case ENOENT: fprintf(stderr,
  1476. X       "message queue does not exist (ENOENT)\n");
  1477. X       break;
  1478. X   case ENOSPC: fprintf(stderr,
  1479. X       "too manny message queus (ENOSPC)\n");
  1480. X       break;
  1481. X   case EEXIST: fprintf(stderr,
  1482. X       "message queue exists, but locked out (EEXIST)\n");
  1483. X       break;
  1484. X   default: fprintf(stderr,
  1485. X       "unknown error (%n)",errno);
  1486. X       break;
  1487. X   }
  1488. Xreturn(0);
  1489. X}
  1490. X
  1491. X/************ serror **********************
  1492. X ** prints out the errormessage associate with a semaphore
  1493. X ***************************************************************/
  1494. Xserror(s)
  1495. Xchar *s; /* message prefix string */
  1496. X{
  1497. Xextern int errno;
  1498. X
  1499. Xfprintf(stderr,"SEMAPHORE ERROR: %s:\n     ",s);
  1500. Xswitch(errno)
  1501. X   {
  1502. X   case EINVAL: fprintf(stderr,
  1503. X       "invalid number of semaphore sets (EINVAL)\n");
  1504. X       break;
  1505. X   case EACCES: fprintf(stderr,
  1506. X       "semaphore exists, but invalid operation (EACCES)\n");
  1507. X       break;
  1508. X   case ENOENT: fprintf(stderr,
  1509. X       "semaphore does not exist (ENOENT)\n");
  1510. X       break;
  1511. X   case ENOSPC: fprintf(stderr,
  1512. X       "too many semaphores (ENOSPC)\n");
  1513. X       break;
  1514. X   case EEXIST: fprintf(stderr,
  1515. X       "semaphore exists, but locked out (EEXIST)\n");
  1516. X       break;
  1517. X   default: fprintf(stderr,
  1518. X       "unknown error (%n)",errno);
  1519. X       break;
  1520. X   }
  1521. X}
  1522. X
  1523. X
  1524. END_OF_FILE
  1525. if test 15460 -ne `wc -c <'dbmserv.c'`; then
  1526.     echo shar: \"'dbmserv.c'\" unpacked with wrong size!
  1527. fi
  1528. chmod +x 'dbmserv.c'
  1529. # end of 'dbmserv.c'
  1530. fi
  1531. echo shar: End of archive 3 \(of 5\).
  1532. cp /dev/null ark3isdone
  1533. MISSING=""
  1534. for I in 1 2 3 4 5 ; do
  1535.     if test ! -f ark${I}isdone ; then
  1536.     MISSING="${MISSING} ${I}"
  1537.     fi
  1538. done
  1539. if test "${MISSING}" = "" ; then
  1540.     echo You have unpacked all 5 archives.
  1541.     rm -f ark[1-9]isdone
  1542. else
  1543.     echo You still need to unpack the following archives:
  1544.     echo "        " ${MISSING}
  1545. fi
  1546. ##  End of shell archive.
  1547. exit 0
  1548. exit 0 # Just in case...
  1549.